from xml.sax.saxutils import escape
from re import compile
from parser import Parser

"""
TODO: Take care that keywords in contexts like import %s, import %s
from are not stored as variables
"""

class LanguageParser(Parser):
    '''
    This parser substitutes all user defined identifiers through
    sympy, symbide and python identifiers. Which translations are
    carried out, can be modified.
    '''
    
    #The order is essential! If the same identifiers are declared
    #in different sections, the front sections are in favor
    funcNames = ['symbideFunction', 'sympyFunction', 'sympyMethod', 'pythonFunction']
    keywordNames = ['sympyConstant', 'pythonKeyword']
    
    #everything inside the following tags is ignored
    tags = (('<string>','</string>'),)
    
    #All not recognized functions and keywords are stored in this lists
    functions = []
    variables = []        
    
    def parse(self, text, mode=0, **args):
        '''
        Translates either all identifiers to keywords (mode=0), or all keywords
        to identifers (mode=1). All not recognized keywords ands functions are 
        returned in separate lists.
        
        By default it carries out all possible substitutions. This can be changed
        through additional arguments. Possible adjustments are:
            - sympyFunction
            - sympyMethod
            - sympyConstant
            - pythonKeyword
            - pythonFunction
            - symbideFunction
            - sympyModifier
        '''
        
        assert mode in (0, 1)
        
        self.flags = {'sympyKeyword':True,
                      'sympyMethod':True,
                      'sympyConstant':True,
                      'pythonKeyword':True,
                      'pythonFunction':True,
                      'symbideFunction':True,
                      'sympyModifier':'sympy.'}
        
        self.flags.update(args)
        self.mode = mode
        self.variables = []
        self.functions = []
        
        text = self.parseKeywords(text)
        text = self.parseFunctions(text)
        return text, self.variables, self.functions
        
    def parseKeywords(self, text):
        '''
        Substitutes all keywords that are found in the translation table. All
        other keyword-like names are encapsulated with __variables__["%s"].
        Strings are left alone.
        '''
        
        self._updateTranslationTable(self.keywordNames)
        self._updateTagsList(text)
        def subst(name):
            if self._insideTag(name.start()):
                return name.group()
            elif name.group() in self.translation[0]:
                return name.group()
            else:
                self.variables.append(name.group())
                return name.group()
        return self.settings.pattern['variable'].sub(subst, text)
               
    def parseFunctions(self, text):
        '''
        Substitutes all functions that are found in the translation table. All
        other function-like names are encapsulated with __functions__["%s"].
        Strings are left alone.
        '''
        
        self._updateTranslationTable(self.funcNames)
        self._updateTagsList(text)
        
        def subst(name):
            if self._insideTag(name.start()):
                return name.group()
            elif name.group() in self.translation[0]:
                return name.group()
            else:
                self.functions.append(name.group())
                return name.group()
        return self.settings.pattern['function'].sub(subst, text)
        
    def _updateTranslationTable(self, names):
        '''
        creates a table where all identifiers and their corresponding keywords
        are stored in the form:
        [(identfier1, identifier2, ...),(keyword1, keyword2, ...)]
        
        With names it is specified what keywords are considered. The order of
        names is important, because if two identifiers are equal that one in the
        first listed namespace will succeed.
        '''
        
        self.translation = []
        
        m1 = self.mode
        if m1==0:
            m2=1
        else:
            m2=0
        
        for n in names:
            for keys in self.settings.keywords[n]:
                self.translation.append(keys[m1])